﻿Imports System.Security.Cryptography
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.IO
Namespace Pop.Api.Util
    Public Class TopUtils

        Private Const Boundary As String = "--------------------------------ThIs_Is_tHe_bouNdaRY_$"

#Region "创建签名"

        ''' <summary>
        ''' 创建本次调用的签名
        ''' </summary>
        ''' <param name="Url">API协议文档指定的提交目标URL</param>
        ''' <param name="Fields">参数列表</param>
        ''' <param name="SecretKey">用户session</param>
        ''' <returns>String，签名</returns>
        Friend Shared Function GetSign(ByVal Url As String, ByVal Fields As List(Of FormField), ByVal SecretKey As String) As String
            Dim temp As FormField
            If Url.IndexOf("?charset=utf-8") <> -1 Then Fields.Add(New StringField("charset", "utf-8"))
            For j As Integer = 1 To Fields.Count - 1
                For i As Integer = 0 To Fields.Count - j - 1
                    If String.Compare(Fields(i).Key, Fields(i + 1).Key, StringComparison.Ordinal) > 0 Then
                        temp = Fields(i)
                        Fields(i) = Fields(i + 1)
                        Fields(i + 1) = temp
                    End If
                Next
            Next

            Dim source As New StringBuilder
            Dim preKey As String = String.Empty
            For Each Field As FormField In Fields
                If Field.GetType.Equals(GetType(FileField)) Then Continue For
                If Not preKey.Equals(Field.Key) Then
                    preKey = Field.Key
                    source.Append(Field.Key)
                End If
                source.Append(Field.Value)
            Next
            '添加url
            source.Insert(0, Regex.Match(Url, "(?<=ttp://api.paipai.com/)[^.]+").Value.Replace("/", "."))
            source.Append(SecretKey)
            Return MD5(source.ToString)
        End Function

        Private Shared Function MD5(ByVal strInput As String) As String
            Dim md5c As New MD5CryptoServiceProvider
            Dim bytHash As Byte() 'bytValue As Byte()
            'bytValue = Encoding.UTF8.GetBytes(strInput)
            bytHash = md5c.ComputeHash(Encoding.UTF8.GetBytes(strInput))
            md5c.Clear()
            Dim sTemp As New StringBuilder
            For i As Integer = 0 To bytHash.Length - 1
                sTemp.Append(bytHash(i).ToString("X").PadLeft(2, "0"c))
            Next
            Return sTemp.ToString.ToLower
        End Function

#End Region

#Region "组装包体"
        ''' <summary>
        ''' 组装HTTP请求包的包体内容
        ''' </summary>
        ''' <param name="Fields">fields，参数列表</param>
        ''' <returns>包体内容</returns>
        Friend Shared Function MultipartData(ByVal Fields As List(Of FormField)) As List(Of Byte)
            Dim list As New List(Of Byte)
            Try
                For Each field As FormField In Fields
                    If field.GetType.Equals(GetType(StringField)) Then
                        If field.Key.Equals("charset") OrElse field.Key.Equals("sign") Then Continue For
                        list.AddRange(CByteStringField(field))
                    Else
                        list.AddRange(CByteFileField(field))
                    End If
                Next
                list.AddRange(ToList(Encoding.UTF8.GetBytes("--" & Boundary & "--" & vbCrLf)))
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
            Return list
        End Function
        Private Shared Function CByteStringField(ByVal Field As StringField) As List(Of Byte)
            Dim body As New StringBuilder
            body.Append("--" & Boundary & vbCr & vbLf)
            body.Append("Content-Disposition: form-data; name=""" & Field.Key & """")
            body.Append(vbCr & vbLf)
            body.Append("Content-Type: text/plain; charset=utf-8" & vbCr & vbLf)
            body.Append(vbCr & vbLf)
            body.Append(Field.Value & vbCr & vbLf)
            Return ToList(Encoding.UTF8.GetBytes(body.ToString))
        End Function
        Private Shared Function CByteFileField(ByVal Field As FileField) As List(Of Byte)
            Dim body As New StringBuilder
            Dim list As New List(Of Byte)
            body.Append("--" & Boundary & vbCr & vbLf)
            body.Append("Content-Disposition: form-data; name=""" & Field.Key & """")
            body.Append("; filename=""" & Field.Value & """" & vbCr & vbLf)
            'body.Append("Content-Type: image/jpeg")
            body.Append("Content-Type: application/octet-stream" & vbCr & vbLf)
            body.Append("Content-Transfer-Encoding: binary" & vbCr & vbLf & vbCr & vbLf)
            list.AddRange(ToList(Encoding.UTF8.GetBytes(body.ToString)))
            list.AddRange(CByteFileStream(Field.Value))
            Return list
        End Function
        Private Shared Function CByteFileStream(ByVal FilePath As String) As List(Of Byte)
            Dim fileStream As New FileStream(FilePath, FileMode.Open, FileAccess.Read)
            Dim buffer(1024 * 2048 - 1) As Byte
            Dim memStream As New MemoryStream
            Dim bytesRead As Integer = 0
            Do
                bytesRead = fileStream.Read(buffer, 0, buffer.Length)
                memStream.Write(buffer, 0, bytesRead)
            Loop While bytesRead <> 0
            fileStream.Close()
            Return ToList(memStream.GetBuffer)
        End Function
        Private Shared Function ToList(ByVal data() As Byte) As List(Of Byte)
            Dim list As New List(Of Byte)
            For Each d As Byte In data
                list.Add(d)
            Next
            Return list
        End Function
#End Region

#Region "原SDK函数"

        Friend Shared Function RetriveParamInURL(ByVal strUrl As String) As List(Of FormField)
            Dim list As New List(Of FormField)
            Dim strParams As String = strUrl.Substring(strUrl.IndexOf("?"c))
            If strParams.Length = 0 Then Return list
            strParams = strParams.Substring(1)
            Dim cSpliter As Char() = {"&"c}
            Dim strParamList As String() = strParams.Split(cSpliter, Integer.MaxValue)
            For Each parampair As String In strParamList
                Dim strKey As String = parampair.Substring(0, parampair.IndexOf("="c))
                Dim strValue As String = parampair.Substring(parampair.IndexOf("="c))
                If 0 < strValue.Length Then
                    strValue = strValue.Substring(1)
                End If
                list.Add(New StringField(strKey, strValue))
            Next
            Return list
        End Function

        ''' <summary>
        ''' 基于字符编码进行比较
        ''' </summary>
        ''' <param name="strA">strA，第一个字符串</param>
        ''' <param name="strB">strB，第二个字符串</param>
        ''' <returns>1，strA比strB大；-1，strA比strB小；0，strA等于strB</returns>
        Friend Function CompareByAscii(ByVal strA As String, ByVal strB As String) As Integer
            Dim chArrA As Char() = strA.ToCharArray()
            Dim chArrB As Char() = strB.ToCharArray()
            Dim countA As Integer = strA.Length
            Dim countB As Integer = strB.Length
            Dim countCompare As Integer = If((countA < countB), countA, countB)
            For i As Integer = 0 To countCompare - 1
                If chArrA(i) < chArrB(i) Then Return -1
                If chArrA(i) > chArrB(i) Then Return 1
            Next
            If countA < countB Then Return -1
            If countA > countB Then Return 1
            Return 0
        End Function

        ''' <summary>
        ''' 把十六进制的字符串去掉前缀0x，并把小写字母变成大写，如0xae00cf => "AE00CF "
        ''' </summary>
        ''' <param name="bytes">bytes，转化前的内容</param>
        ''' <returns>string，转化后的内容</returns>
        Friend Shared Function ToHexString(ByVal bytes As Byte()) As String
            ' 0xae00cf => "AE00CF "
            If IsNothing(bytes) Then Return String.Empty
            Dim strB As New StringBuilder()
            For i As Integer = 0 To bytes.Length - 1
                strB.Append(bytes(i).ToString("X2"))
            Next
            Return strB.ToString()
        End Function
#End Region

    End Class
End Namespace